using System;
using System.Collections.Generic;
using System.Text;
using System.Diagnostics;


namespace WozLib.UI.Ink.SketchObjects
{
  public class SketchObjectRegistry
  {
    private Dictionary<long,ISketchObject> _WozObjects = new Dictionary<long,ISketchObject>();

    // we need these to be static so that we don't get collision
    private static long _NextServerID = 0;

    const long NextClientID_SEED = 10000000;
    private static long _NextClientID = NextClientID_SEED;

    // just a lock object for _NextClientID & _NextServerID
    private static List<ISketchObject> dummy = new List<ISketchObject>();

    // Indicates whether objects added to the registry should be added as a server object
    public bool ServerMode
    {
      get { return _ServerMode; }
      set { _ServerMode = value; }
    } private bool _ServerMode = false;


    public SketchObjectRegistry()
    {
    }

    private void RegisterClientObject(ISketchObject wozObject)
    {
      long id = long.MinValue;

      // lock on Woz Object Dictionary so we can prevent handing out duplicate IDs
      lock (dummy)
      {
        // Get the next ID
        id = _NextClientID;

        // Increment the next ID
        _NextClientID++;
      }

      RegisterObject(wozObject, id);

      Debug.WriteLine("Registered " + wozObject.ToString() + " with ID: " + id.ToString());
    }

    private void RegisterServerObject(ISketchObject wozObject)
    {
      long id = long.MinValue;

      // lock on Woz Object Dictionary so we can prevent handing out duplicate IDs
      lock (dummy)
      {
        // Get the next ID
        id = _NextServerID;

        // Increment the next ID
        _NextServerID++;
      }

      RegisterObject(wozObject, id);

      Debug.WriteLine("Registered " + wozObject.ToString() + " with ID: " + id.ToString());
    }

    public void RegisterObject(ISketchObject wozObject)
    {
      if (this.ServerMode)
      {
        RegisterServerObject(wozObject);
      }
      else
      {
        RegisterClientObject(wozObject);
      }
    }

    private void RegisterObject(ISketchObject wozObject, long id)
    {
      // Assign the Woz Object the next ID
      wozObject.WozID = id;

      // Add the object to the registry using the ID
      _WozObjects.Add(id, wozObject);
    }

    public void RegisterObjectWithExisitingId(ISketchObject wozObject)
    {
      try
      {
        _WozObjects.Add(wozObject.WozID, wozObject);

        if (wozObject.WozID < NextClientID_SEED && _NextServerID <= wozObject.WozID)
          {
            _NextServerID = wozObject.WozID + 1;
          }
        else
        {
          if (wozObject.WozID >= NextClientID_SEED && _NextClientID <= wozObject.WozID)
          {
            _NextClientID = wozObject.WozID + 1;
          }
        }
      }
      catch (Exception ex)
      {
        Debug.WriteLine("Object Registry: " + ex.ToString());
        if (wozObject != null)
        {
          Debug.WriteLine("               : Exception thrown during object addition ("
            + wozObject.ToString() + " with ID " + wozObject.WozID.ToString() +
            "). That key probably already exisits");
        }
      }
    }

    public bool ContainsObject(long WozID)
    {
      return _WozObjects.ContainsKey(WozID);
    }

    public ISketchObject GetObject(long WozID)
    {
      if (_WozObjects.ContainsKey(WozID))
      {
        return _WozObjects[WozID];
      }
      else
      {
        return null;
      }
    }


    internal void Clear()
    {
      this._WozObjects.Clear();
    }
  }
}
